type ThrottledFunction<T extends (...args: any[]) => any> = (...args: Parameters<T>) => ReturnType<T>;

/**
 * @description 脱敏处理
 * @param str 需要处理的原字符串
 * @param options
 * start 开始显示字符个数，默认4
 * end 末尾显示字符个数，默认4
 * chart 替换的字符 默认 *
 * len 替换字符需要出现的次数，默认1 例如: len = 2 => **** ****
 * num 字符挨着出现的次数 默认4，例如：****, num = 2 => **
 * prefixChart 替换字符的前缀，默认空格，例如:prefixChart = # =>  #****
 * suffixChart 替换字符的后缀，默认空格，例如:suffixChart = # =>  ****#
 */
export const desensitization = (
  str: string,
  options: {
    start: number;
    end: number;
    len: number;
    num: number;
    chart: string;
    prefixChart: string;
    suffixChart: string;
  }
) => {
  if (!str) return "";
  options = Object.assign({ start: 4, end: 4, len: 1, num: 4, chart: "*", prefixChart: " ", suffixChart: " " }, options);
  let { start, end, len, num, chart, prefixChart, suffixChart } = options;
  str = str.toString();
  if (start < 0 || end < 0 || len < 1 || num < 1) {
    throw TypeError("参数类型错误");
  }
  const startChar = str.slice(0, start);
  const endChart = str.slice(0 - end);
  let middle = "";
  let charLen = "";
  for (let i = 0; i < num; i++) {
    charLen += chart;
  }
  for (let i = 0; i < len; i++) {
    middle += prefixChart + charLen;
  }
  middle = middle + suffixChart;
  return startChar + middle + endChart;
}

/**
 * @description 节流
 * @param callback 回调
 * @param limit 时间
 * @returns {ThrottledFunction<T>}
 */
export function throttle<T extends (...args: any[]) => any>(callback: T, limit: number): ThrottledFunction<T> {
  let inThrottle: boolean = false;
  return (...args: Parameters<T>) => {
    if (!inThrottle) {
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
      return callback(...args);
    }
  };
}

/**
 * @description 防抖
 * @param func 回调
 * @param delay 时间 
 * @returns {T}
 */
export function debounce<T extends (...args: any[]) => any>(func: T, delay: number = 0, context?: any): T {
  let timeoutId: number | undefined;
  const debouncedFunc = function (...args: any[]) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      func.apply(context, args);
    }, delay);
  };
  return debouncedFunc as T;
}

/**
 * @description 深克隆
 * @param obj 克隆对象
 * @returns 返回新对象
 */
export const deepClone = <T>(obj: T): T => {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  if (obj instanceof Date) {
    return new Date(obj.getTime()) as any;
  }
  if (obj instanceof Array) {
    const newArr = [];
    for (let i = 0; i < obj.length; i++) {
      newArr[i] = deepClone(obj[i]);
    }
    return newArr as any;
  }
  if (obj instanceof Object) {
    const newObj: any = {};
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        newObj[key] = deepClone(obj[key]);
      }
    }
    return newObj as any;
  }
  return obj;
}